package md.specialEqp;

import lombok.*;
import md.cm.unit.Unit;
import md.system.User;
import org.fjsei.yewu.filter.Uunode;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;

import static jakarta.persistence.FetchType.LAZY;


/**通用的申请单：保证授权操作安全前提下的充分的可适应性扩展性。？如何恰当建模? 申请单来讲实际很多情况都可以信任最后环节操作人可直接前端进行业务接口操作的。
 * 发起人提交，预定义内容模板，框架化配置流程BPMN可适应的，批准最后通过之后的授权操作或动作的按规定作业。
 * 操作前置条件： 后端参数的理解解析，前端后端配合，前端自主发起操作适当性。
 * 【正常的】请求事情审批，逐级缩小角色覆盖，往前流转一个节点，操作权限就会提升一级别，最后审批人的权力最大。最终触发的后端操作也就仰仗最后审批角色授权。
 * 申请单创建到审批执行结束的周期一般是短暂的，历史记录如何追溯搜索？快捷的溯源。数据保留期限几年啊？外部对象可能会关联到本实体。
 * 发起人应该事先准备好操作参数集合【】，审批人查看核准以后，后台或者是最后一关UserTask(前端的)或WorkerJob(后端的)执行授权的实际操作。
 * 问题在于：可以信任最后批准人的非预期篡改前面节点参数吗？？否则前端直接做透明业务接口会带来严肃问题！ 申请单都会在批准通过后需要运行预先安排的业务操作接口。
 * 是否认可最后批准人或最后节点人(正常申请单核准后的业务操作执行时机)，是否信任最后批准人代为操作业务接口？？不认可的只能在后端嵌入业务操作代码了！
 * 【考虑】本实体仅维持活跃或近期热数据。历史申请单很久都没啥用处的应该移出去，在另外搞一个模型：过往的申请单存储对象模型如：OldRequest,或者干脆？。
 * */

@Getter
@Setter
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Builder(toBuilder=true)
//@Cacheable 升级版本用的!
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region = "Fast")
public class Request implements Uunode {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private UUID id;
    //JPA特殊对待？ 必须空表才能新建 @Version 字段？正常都应当添加 version 字段？#多个web浏览器前端一起更新同一个对象,大家读取到的数据都会是对于别人来说是旧的数据。
    //数据库直接修改的，后端服务器缓存并不是最新数据的，就会导致缓存中的数据来更新物理数据库。@Cache缓存#会导致(不是同一个后端协调约束的数据库)不一致!!version++加上后可以不覆盖旧的。
    //数据类型用int比较好，够大能区分：用JPA中@Version来做web浏览后再更新的非数据库事务的面对业务层面并发读写控制。
    //乐观锁同步用，［注意］外部系统修改本实体数据就要改它version后一起commit事务。@Version防第二类更新丢失；外部更新version，我这读取依然受缓存影响。
    @Version
    private int  version;

    /*流程框架参数 ： BPMN关键配置变量。
     * BPMN 参考流程节点装配样式。
     * 请假单1天还是5天在创建人提交时刻就已经确认：定下了流程到底要1个节点还是3个节点审核。前端设置错误导致后续后端或者最后一步批准接口操作人会无权限执行的错误。
     */
//    @Deprecated
//    private String  type;

    /**字典？前端自定义模板名称 :前端form组件和适当展示内容。
     * 需要依据这个关键标识去判定是否执行后端业务接口操作的嵌入代码。代码耦合前端配置==“代码管理维护的陷阱”,zeebe代码数据的抽离，分层剥离流程状态代码。zeebeWorkerJob（）？？
     * 后端可根据名字来确定aux参数集合。
     * 【关键字】不适合前端授权操作的，需要在后端进行实际操作的情况(临时过程状态参数转入)？
     * 或者需要分解成两个部分的实际业务操作{前面1部分在最终审批人进行，后面环节附加节点要针对性质补充操作{还可防止被篡改内容？二次确认}}。
     * 防篡改Hash? :一个阶段节点作业人员的内容 该人员操作相对应的Hash; 下一个节点不能篡改上一个节点数据，可以退回流程。 “区块链的味道”
     * 防篡改在流程结束之后就算使命结束了(实际业务操作执行已经结束)，zeebe历史存储和hash校验，用户确认授权。
     * 流程节点后退：每个环节权利人只能负责自己增量数据参数，不然后退给前面节点用户修正后再次流转过来。
     * 为了保证授权安全和业务公正性严格防篡改：需要后端来直接操作业务操作的，不能授权最后一个流程UserTask来执行业务操作的情况{分成两个业务操作接口步骤的？}。
     */
    private String  mod;

    /**不信任模式的，后端要受累了：需要感知流程隐藏json里面的数据结构参数含义。
     * 流程引擎上的增加的 Manual service Task名字？内部路由标签，还是BPMN流程图就已经配置好了节点{case::}
     * action=null,不需要额外执行后端代码{前端代为执行业务操作的？}
     * 前端最后批准人直接执行业务操作接口的(后端不运行业务代码)模式的，此最终User必须有权限执行接口全部命令才行的，后端执行业务操作模式的使用管理员授权和其他服务器对等认证代理User。
     * */
//    private String  action;

    /**申请授权操作的目标是哪一个单位： 特检院;    缺省 =福建省特检院。
     * 报检SDN客户; 本单位检验员；OA申请转接；
     * */
    @NotNull
    @ManyToOne(fetch= FetchType.LAZY)
    @JoinColumn
    private Unit  ispu;

    /**状态：创建中正在申请中，审核过程中，审批完成，（特别申请单）已经批准结束等待监察平台的反馈后才真正允许终结申请单的生命周期=最终结束。取消的。
     * "审批完成"本平台范围处理算结束可是外部平台参与的申请实际业务处理结果反馈可能拖延，需要其他途径来真正结束本申请单状态==》可结束生命周期状态。
     * 协议协商进度：zeebe内部状态主要参考preNode取值+preMan。
     *  流程进度，表征意义，不是和zeebe引擎的BPMN节点一一对应的。
     * 申请单状态：实际是zeebe流程运行环节映射值。其实主要的状态值已经划归流程引擎内置了，引擎运行到了哪一个环节就是某一状态值(不一定对本实体可感知的)。
     * 协议运行状态字。 有些取值仅仅只读反馈用途，不可以当做操作的先决条件或逻辑依据。
     监检 PROTOCOL_STATUS状态，-1,作废，0：申报，1：待审核，2:审核通过，待导出协议等操作，3：提交用户业务受理（协议签订完毕）,4:业务受理申请,5：业务受理终结
     委托 PROTOCOL_STATUS协议状态，-1,作废，0：申报，1：待审核，3：审核通过，提交用户业务受理（协议签订完毕）,4:业务受理申请,5：业务受理终结
     zeebe流程图上节点和这个没有绝对对应关系，这个状态代表大概的关卡也就是流转审批进度。
     不加@Enumerated(EnumType.STRING)默认Enum在数据库存储是int这个可不能随意修改_Enum顺序值。
     */
    @Builder.Default
    @Enumerated(EnumType.STRING)
    private RequestSta_Enum status =RequestSta_Enum.INIT;

    /*关联设备, 多台；
     * 安装监检，管道的如何初始化设备台账：必须先登记关键主键字段信息，其它的允许补齐其它参数字段？影响到计费必须首先录入到台账，
     * 未注册的监察平台还没有的设备:报检用户申报的新设备也得初始化台账后再来走这个协议计费计算依据的除外，或者收费计算按量计价没事前明确最终金额数值的也是允许。
     * 正常协议受理完毕不能修改设备列表了不再生成任务新Task，框架协议承包形式的大合同情况？才允许在协议受理结束之后还能够调整关联设备列表。
     * 新设备正常由检验人员或窗口受理人员新添加Eqp。 水质或制造监检或其它未能进入设备台账管控的非常规业务的情况没有这个关联信息。
    * */
//    @ManyToMany
//    @JoinTable
//    @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL,region ="Fast")
//    private List<Eqp>  devs;

    /*申请单位，签订业务协议的单位。 不一定等于设备台账的使用单位。
     * 报检SDN用户归属单位必须是在Unit存在的{使用单位}。否则走只能代理方式：委托电梯公司承包，关联设备才需要使用单位的。
     * 其它未能进入设备台账管控的如果不在Unit的服务对象：也得首先建立一个新Unit才行;Unit可能特检院就能添加不一定要监察平台映射单位。
     */
//    @ManyToOne(fetch= FetchType.LAZY)
//    @JoinColumn
//    private Unit  servu;

    /**创建人， 归属某个部门。 SDN客户针对某个检验机构的特定部门？
     * 登记人，主体内容发起人。  ==流程图的author字段
     * */
    @ManyToOne(fetch= FetchType.LAZY)
    private User crman;

    /**直接领导签注 : 文员？受理人员环节； SDN客户针对某个检验机构的前台接待人员。
     * 本检验单位的协调人员。
     * 这个角色没有操作数据参数。 director
     * */
    @ManyToOne(fetch= FetchType.LAZY)
    private User director;

    /**主管部门领导签注， 两阶段两个级别审批批准模式的，需要设置前置审核人。
     * */
    @ManyToOne(fetch= FetchType.LAZY)
    private User manager;

    //可以信任最后批准人的才能在前端直接做业务实际操作，不能相信的做法：拆分业务操作+交给后端服务器代为运行{数据没有被篡改的}。
    //创建人，最后批准人，  ：直接负责人， 主管部门负责人,  》》已批准，不适合许可，否定意见的直接结束流程？撤回申请单，不撤回的保留意见(不合格报告不准通过)的继续流转。业务接口命令如何设置？

    /**谁负责最后一关口的审核人，最后批准人。
     *主要4个人：最多见过后续四个环节：创建时的签名还不算的，直接领导签注，主管部门领导签注，最高一级签注最后批准核准，创建人还得回头再次签注意见，但此案例需要后端操作最后一关不适合前端直接授权而操作：校核作业和申请登记流程分离。
     * 请假申请条？：请1天，请5天需要审批人不一样，请假类型：年休病假事假审核最高需要主管，还是公司大领导审批才能算数的，最后一步骤批准人执行业务操作：允许核销考勤期间操作：权限和天顺过滤：部长角色可以最多操作接口的参数后端判定。
     * */
    @ManyToOne(fetch= FetchType.LAZY)
    private User auditor;

    /*建议保留活跃的期限到； 冷数据拆离；
     * 这个日期过后，（批量认定）非活跃的历史数据。  删除申请单谨慎。  依据mod来判定
     * */
//    private LocalDate  activDate;

    /**外部Manual Task环节的超时天数：（特别申请单）已经批准结束等待监察平台的反馈后才真正允许终结申请单的生命周期=最终结束。
     * 若status=审批完成 && mdtime + days过了还没有有监察平台反馈的，自动处理本身清单的最终结束,#同时mdays归零。
     * mdays=0|null的可以省略本环节。 需等待监察平台的反馈的一类申请单才需要设置。默认的审批完成就能直接==>最终结束。
     * 【冷数据问题】本单子直接转为“中止监检通知书”的存储依赖的情况：客户有可能不是User，不能确认客户一定就不再需要看“通知书”了，那么本实体的生存期应该特别需要拉长！mdays设置2年后才会撤销前端可见性，2年还会需要看通知书？告知单：
     * 若status=END的也不能立刻删除，依据mod + mdays +mdtime来判定能否删除或者转移到历史申请单保留存储库去。
     * */
    private Short  mdays;
    /**最新修改时间。新创建申请单=最新的。
     *未生效的协议等同=申请单的修改时间， 生成的时间。
     * */
    private LocalDateTime  mdtime;

    /**创建人编制参数部分。每一个角色只能允许修改本人的数据。
     * 【权衡考虑】决定采用非结构化的方案。表单或允许走非结构化形式的更多的前端自定义扩充的字段；非结构化的优点，弱点。非结构化数据一致性较差，前端graphQL无法内省,存储空间要求增大。
     * 兼容很多不同的申请单的 各种可能的内嵌编辑内容字段，
     * 可惜JSON非结构化的弊端需要考虑(DB上做过滤搜索/关联约束)，不行只能抽出来放入@Entity模型中。
     * 非实时定期一年做一回的统计需求还好说：json可以提取走大数据统计模式。
     * 注意！ 实时过滤或统计有硬性需求的字段就不能塞入json中。JPA实体关系关联也是没法graphQL内省。离线统计可以容忍json化。对ES搜索来讲的非结构化也是能一点程度接纳？。
     * 类似zeebe的表单概念form;
     * 前端保存需要转换 data:  JSON.stringify(storage || source) ,提取也要转const  svp = JSON.parse(getDeviceSelf?.svp || '{}');
     * 非结构化json字段内容dat无法内省:适应性局限。前端只能看见你是关联对象id+部分存储在json中的字段历史数据并非最新的，获取最新数据必须单独跳转链接或再次发起查询Query node(id)。
     * 【主要理由】Request要适配前端业务种类繁多，实体字段信息要求的多样性要求非常大，若都用结构化JPA关联的话Request表字段数联合派生表会爆多，删除对象等操作关联越多的管理越麻烦，JSON非结构化带来的好处和坏处权衡考察！。
     * 缺点，就像中止监督检验通知书关联Task的，也需要直接在后台生成时就快照task服务单位名，设备使用单位名，设备种类名，这些需要在通知书显示字段，免被动态修改？免前端需要多次查询关联数据:前端还需要隐含保存此类字段(#信赖前端用户不瞎改掉@)。
     */
    @Lob
    @Basic(fetch=LAZY)
    @Column( columnDefinition="jsonb")
    private String  dat;

    /*创建人编制参数部分的Hash校验
     * 若不信任，前端进行业务接口操作模式都是可能被篡改的，所以总归防御机制失效！！
     */
//    private String  ash;


    /*是否认可最后批准人或最后节点人(正常申请单核准后的业务操作执行时机)，是否信任最后批准人代为操作业务接口？？不认可的只能在后端嵌入业务操作代码了！
     * 是否还需要后端执行授权的操作？附带后端知晓的解析参数，前端的意图后端必须知晓的模式。
     * 所以：能在前端发起操作的，就尽量不用后端做。@@ 相互的代码上的关联性问题 嵌入的太大了!。
     * 关联关系管理太过于脱节和不受控制。 需要提取aux字段数据太糟糕，违反OOP单一职责原则。
     * 遇见这丫的：创建人还得回头再次签注意见，但此案例需要后端操作最后一关不适合前端直接授权而操作，需要后端公正操作吧。
     * */
//    private Boolean  related;


    /*审核人备忘录: 针对性保存审核人笔记，不在协议书体现。
     */
    //private String  ckMemo;

    /*流程的 上一个环节处理人。
     * 没有通过 Operate 网站查询流程运行节点的最新视图，无法判定上一个节点干什么的，谁啊。
     * */
//    @ManyToOne(fetch= FetchType.LAZY)
//    private User preMan;

    /**最后一关审核人的输入：意见，非结构化json:支持扩充符合内容字段。
     *物理数据库定义jsonb类型，注意 #容易报错：HHH000315: Exception executing batch [java.sql.BatchUpdateException: Batch entry 0
     * */
    @Lob
    @Basic(fetch=LAZY)
    @Column( columnDefinition="jsonb")
    private String  audat;

    /**第二关的主管部门审核人的输入：意见，非结构化json:支持扩充符合内容字段。
     * */
    @Lob
    @Basic(fetch=LAZY)
    @Column( columnDefinition="jsonb")
    private String  mndat;

    /**第一关直接领导审核人的输入：意见，非结构化json:支持扩充符合内容字段。
     * */
    @Lob
    @Basic(fetch=LAZY)
    @Column( columnDefinition="jsonb")
    private String  drdat;

    /**申请何应答操作结果：仅为文本，仅仅给人看的描述。 @不作为统计依据，没有复合字段：也没单独声明成功失败与否。考虑规范化本字段文本输出：方便扩展需求?=>统计。
     * 【疑虑】有些部分成功执行业务代码，有些算部分失败；有必要吗?:一定统计出某些申请单最终究竟算是成功还是算无效或是执行失败的？或者统计模块代码自动归纳出true/false的结论？？关键字”部分成功“”全部失败“”正常完成“”被拒绝“
     * 可能业务执行端模块留下历史操作记录更为理想方式，文本日志，流水数据库记录。不做申请单关联，但是记录关键字段可跟踪。
     * 若使用@Lob "jsonb"也不方便，大部分还是来自后端的操作而设置，没必要结构化分解出对象类似多个字段，甚至内嵌列表的数组；后端可以只有归纳后注解。
     * 针对需要提交给外部平台如监察平台来处理的申请单，反馈处理结果的。
     * 监察平台消息或接口驱动来变更这个处理结果存储，
     * 申请单具体结果也不需要统计机制，过滤要求？。json:抽取，到底是成功还是失败啊。
     * 【考虑】如果监察平台也需要申请人深度参与的交互回退流程的话？那么就不好控制，这种情况只能让检验员自己去监察平台网站申请了，#本平台就不处理此类申请单了。
     *  */
    //@Lob不一定要
    @Column(length =2000)
    private String  result;

    /*流程上一个环节=入口路径标识， 中文名字。
     * 没有通过 厂家提供的Operate 网站查询流程运行节点的最新视图，无法判定上一个节点干什么的？
     * 子流程可能并发？？最新触发的代码节点, 交叉影响的。
     * 初始化='';
     * 前端针对性显示：有些特别环节需要区分前一个节点的ID差异。
     * 光光依赖实体.status不能表达流程进度条啊：zeebe状态尽量不外露给实体：表示一个流程定义完成一件事情切换最终完成还是取消状态。
     * 而奇怪的是这preNode：透露出zeebe内部节点运行位置线路和状态。也方便反过来追查(不通过Operate网页去查的方式)。
     * */
//    private String  preNode;

    /**生成时间*/
    @Builder.Default
    @Column(updatable = false)
    private LocalDate  crDate= LocalDate.now();


    /**流程实例ID 流程引擎Zeebe返回的关键字。
     * 同一个申请单有可能对prId也会变更的。
     * 流程引擎上面部署的ServiceTask代码和状态分支逻辑要配套地和本申请单实体以及关联的状态字段来综合决定下一步操作。
     * 逻辑状态的在zeebe上肢解和配合。
     * 不一定都是同一个流程Process Id实例, 编制阶段的反复要求提交材料和修改流程？审核(反复要求提交材料)任务阶段流程，后续增补审批流程。
     * prId还可能还会改变啊。 zeebe给的ProcessInstanceKey是long类型。
     * */
    private Long prId;
}




/*CRDB数据库实际上多对多关联的中间表，完全不用单独新建ID作为主键的，可利用复合主键当做PRIMARY KEY,不影响JPA的操作。
    --#ManyToMany中间表修改: 22.2.3版本不需要BEGIN;COMMIT;drop column rowid;简化掉了
* */


/* @数据库修改脚本：

* */